﻿#include "canvas.h"
#include <qdebug.h>
#include <QApplication>
#include <QScreen>
#include <QPainter>


Canvas::Canvas(QWidget *parent)
    : QOpenGLWidget(parent)
{
    setWindowFlags(Qt::Widget | Qt::FramelessWindowHint);

    setAttribute(Qt::WA_AlwaysStackOnTop);          // 让OpenGL最后渲染，否则批注不能透明
    setAttribute(Qt::WA_TranslucentBackground);     // 设置 WS_EX_LAYERD 窗口属性，设置后不能取消

    QSurfaceFormat fmt = format();
    fmt.setSamples(100);
    setFormat(fmt);

    QList<QScreen *> screens = qApp->screens();
    if(screens.empty()) {
        setGeometry(0, 0, 800, 600);
    }
    else {
        QRect rcScr = screens.at(0)->availableGeometry();
        setGeometry(0, 0, rcScr.width(), rcScr.height());
    }

    move(0, 0);
    showMaximized();

    m_iOriginWidth = width();
    m_iOriginHeight = height();
    m_newLine.alpha = 0xFF;
    m_newLine.color = 0xFF0000;
    m_newLine.width = 3;

    m_pToolbar = new Toolbar(nullptr);
    QScreen* pMainScr = qApp->primaryScreen();
    if(pMainScr) {
        int x = (pMainScr->availableGeometry().width() - m_pToolbar->width()) / 2;
        int y = (pMainScr->availableGeometry().bottom() - m_pToolbar->height());
        m_pToolbar->move(x, y);
    }
    else {
        m_pToolbar->move(1000, 500);
    }
    m_pToolbar->show();

    connect(m_pToolbar, &Toolbar::clearPad, this, [this]{
        m_lines.clear();
        m_newLine.points.clear();
        update();
    });

    connect(m_pToolbar, &Toolbar::annotatePad, this, [this]{

        m_bAnnotate = !m_bAnnotate;

        update();
    });

    connect(m_pToolbar, &Toolbar::transPad, this, [this]{
        m_bTrans = !m_bTrans;
        qDebug() << "m_bTrans=" << m_bTrans;

        setAttribute(Qt::WA_TransparentForMouseEvents, m_bTrans);
        setWindowFlag(Qt::WindowTransparentForInput, m_bTrans);
        setWindowFlag(Qt::WindowStaysOnTopHint);

        if(!isVisible()) {
            setVisible(true);
        }

        update();
    });

    connect(m_pToolbar, &Toolbar::scalePad, this, [this]{
        m_bScaleDown = !m_bScaleDown;
        int w;
        int h;
        if(m_bScaleDown) {
            w = m_iOriginWidth / 2;
            h = m_iOriginHeight / 2;
            resize(w, h);
            move(w/2, h/2);
        }
        else {
            w = m_iOriginWidth;
            h = m_iOriginHeight;
            resize(w, h);
            move(0, 0);
        }

        update();
    });

    connect(m_pToolbar, &Toolbar::lineSize, this, [this]{
        if(m_newLine.width == 3) {
            m_newLine.width = 6;
        }
        else {
            m_newLine.width = 3;
        }

        qDebug() << "m_newLine.width=" << m_newLine.width;

        update();
    });

    connect(m_pToolbar, &Toolbar::lineColor, this, [this]{
        if(m_newLine.color == 0xFF0000) {
            m_newLine.color = 0x00FF00;
        }
        else {
            m_newLine.color = 0xFF0000;
        }

        qDebug() << "m_newLine.color=" << m_newLine.color;

        update();
    });

    connect(m_pToolbar, &Toolbar::colorAlpha, this, [this]{
        if(m_newLine.alpha == 0x7F) {
            m_newLine.alpha = 0xFF;
        }
        else {
            m_newLine.alpha = 0x7F;
        }

        qDebug() << "m_newLine.alpha=" << m_newLine.alpha;

        update();
    });

    connect(m_pToolbar, &Toolbar::exitPad, this, [this]{
        qApp->exit(0);
    });
}

void Canvas::initializeGL()
{
    //初始化OpenGL函数
    if (!initializeOpenGLFunctions())
    {
        qDebug() << "init opengl functions failed";
    }

    //设置OpenGL背景色
    glClearColor(1.0f, 1.0f, 1.0f, m_bAnnotate ? 0.0f : 1.0f);

    //使能2D纹理
    glEnable(GL_TEXTURE_2D);

    initTextures();
    initShaders();

    setPicPath(":/img/Screenshot.png");
}

void Canvas::setPicPath(QString path)
{
    if(path.isEmpty()) return;
    m_img.load(path);

    vertices.clear();
    // 计算横坐标长度占窗口的比例

    float xRadio = m_img.width()*1.0/this->width();
    float yRadio = m_img.height()*1.0/this->height();
    if(xRadio < yRadio){
        //顶点坐标
        vertices.append(QVector3D(-1.0*(1.0/yRadio)*xRadio, -1, 1));//左下
        vertices.append(QVector3D(1.0*(1.0/yRadio)*xRadio, -1, 1)); //右下
        vertices.append(QVector3D(-1.0*(1.0/yRadio)*xRadio, 1, 1)); //左上
        vertices.append(QVector3D(1.0*(1.0/yRadio)*xRadio, 1, 1));  //右上
    }
    else {
        //顶点坐标
        vertices.append(QVector3D(-1.0, -1*(1.0/xRadio)*yRadio, 1));//左下
        vertices.append(QVector3D(1.0, -1*(1.0/xRadio)*yRadio, 1)); //右下
        vertices.append(QVector3D(-1.0, 1*(1.0/xRadio)*yRadio, 1)); //左上
        vertices.append(QVector3D(1.0, 1*(1.0/xRadio)*yRadio, 1));  //右上
    }
//    qDebug()<<__FUNCTION__<<xRadio<<yRadio<<vertices;


    picChange = true;


    update();
}

void Canvas::paintGL()
{
    //设置OpenGL背景色
    glClearColor(1.0f, 1.0f, 1.0f, m_bAnnotate ? 0.0f : 1.0f);

    //清空颜色缓存
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    //将OpenGL视口和窗口保持相同
    glViewport(0, 0, width(), height());
    glShadeModel(GL_SMOOTH);

    // draw image
    if(picChange){
        texture->destroy(); //消耗底层的纹理对象
        texture->create();
        texture->setData(m_img);
        picChange = false;
    }

    QMatrix4x4 matrix;
    matrix.translate(0.0, 0.0, -5.0);                   //矩阵变换
    program.enableAttributeArray(0);
    program.enableAttributeArray(1);
    program.setAttributeArray(0, vertices.constData());
    program.setAttributeArray(1, texCoords.constData());
    program.setUniformValue("texture", 0); //将当前上下文中位置的统一变量设置为value
    if(texture){
        texture->bind();  //绑定纹理
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);//绘制纹理
        texture->release(); //释放绑定的纹理
    }
    else {
        qDebug()<<__FUNCTION__<<"纹理没有加载";
    }

    // 历史线条渲染
    foreach (LineParams line, m_lines) {
        DrawLine(line);
    }

    // 当前鼠标画线
    if(!m_newLine.points.empty()) {
        DrawLine(m_newLine);
    }
}

void Canvas::resizeGL(int w, int h)
{
    glViewport(0, 0, w, h);
}

void Canvas::mousePressEvent(QMouseEvent *event)
{
    m_bMouseDown = true;
    QWidget::mousePressEvent(event);
}

void Canvas::mouseReleaseEvent(QMouseEvent *event)
{
    m_bMouseDown = false;
    if(m_newLine.points.size() > 1) {
        m_lines.push_back(m_newLine);
        update();
    }

    m_newLine.points.clear();

    QWidget::mouseReleaseEvent(event);
}

void Canvas::mouseDoubleClickEvent(QMouseEvent *event)
{
    QWidget::mouseDoubleClickEvent(event);
}

void Canvas::mouseMoveEvent(QMouseEvent *event)
{
    if(m_bMouseDown)
    {
        m_newLine.points.push_back(event->pos());
        update();
    }

    QWidget::mouseMoveEvent(event);
}

void Canvas::initTextures()
{
    // 加载 Avengers.jpg 图片
    texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
    texture->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear);
    texture->setMagnificationFilter(QOpenGLTexture::Linear);
    //重复使用纹理坐标
    //纹理坐标(1.1, 1.2)与(0.1, 0.2)相同
    texture->setWrapMode(QOpenGLTexture::Repeat);
//    //设置纹理大小
//    texture->setSize(this->width(), this->height());
    //分配储存空间
    texture->allocateStorage();
}

void Canvas::initShaders()
{
    //纹理坐标
   texCoords.append(QVector2D(0, 1)); //左上
   texCoords.append(QVector2D(1, 1)); //右上
   texCoords.append(QVector2D(0, 0)); //左下
   texCoords.append(QVector2D(1, 0)); //右下

       QOpenGLShader *vshader = new QOpenGLShader(QOpenGLShader::Vertex, this);
       const char *vsrc =
               "attribute vec4 vertex;\n"
               "attribute vec2 texCoord;\n"
               "varying vec2 texc;\n"
               "void main(void)\n"
               "{\n"
               "    gl_Position = vertex;\n"
               "    texc = texCoord;\n"
               "}\n";
       vshader->compileSourceCode(vsrc);//编译顶点着色器代码

       QOpenGLShader *fshader = new QOpenGLShader(QOpenGLShader::Fragment, this);
       const char *fsrc =
          // "precision mediump float;\n" // 添加此行指定float类型的精度为mediump
           "uniform sampler2D texture;\n"
           "varying vec2 texc;\n"
           "void main(void)\n"
           "{\n"
           "    gl_FragColor = texture2D(texture, texc);\n"
           "}\n";
       fshader->compileSourceCode(fsrc); //编译纹理着色器代码

       program.addShader(vshader);//添加顶点着色器
       program.addShader(fshader);//添加纹理碎片着色器
       program.bindAttributeLocation("vertex", 0);//绑定顶点属性位置
       program.bindAttributeLocation("texCoord", 1);//绑定纹理属性位置
       // 链接着色器管道
       if (!program.link()){
           close();
       }
       // 绑定着色器管道
       if (!program.bind())
           close();


}

QPointF Canvas::winPt2GlPt(QPoint winPt)
{
    // OpenGL坐标系宽高
    float maxX = width() / 2;
    float maxY = height() / 2;

    float x = (winPt.x() - maxX) / maxX;       // 窗口坐标系到OpenGL坐标系的转换 -- 平移 --> 缩放
    float y = -(winPt.y() - maxY) / maxY;      // 平移 --> 反向 --> 缩放
    return QPointF(x, y);
}

void Canvas::DrawLine(const LineParams& line)
{
    float r =(line.color >> 16) / 255.0f;
    float g =((line.color & 0x00FF00) >> 8) / 255.0f;
    float b =(line.color & 0x0000FF) / 255.0f;
    glColor4f(r, g, b, line.alpha / 255.0f);
    glLineWidth(line.width * 1.0f);

    glBegin(GL_LINE_STRIP);
    foreach (QPoint pt, line.points) {
        QPointF glPt = winPt2GlPt(pt);
        glVertex3f( glPt.x(), glPt.y(), 0.0f);
    }
    glEnd();
}

void Canvas::DrawImage(const ImageParams& image)
{
    ;
}

